﻿using System;
using System.Collections.Generic;
using System.Linq;

using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.AdoNet;
using NHibernate.Connection;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Mapping.ByCode;
using NHibernate.Bytecode;
using Laugh.Environment;
using NHibernate.Mapping.ByCode.Conformist;

namespace Laugh.Data.DatabaseCfg
{
    public class DatabaseBuilder : IDatabaseBuilder
    {
        private NHibernate.Cfg.Configuration _config;
        private bool _hasAddedMappingClass = false;
        private string _name = "default";

        public DatabaseBuilder()
        {
            _config = new NHibernate.Cfg.Configuration();
        }

        public IDatabaseBuilder Named(string name)
        {
            _name = name;
            return this;
        }

        public IDatabaseBuilder UsingDatabase(DatabaseType dbType)
        {
            _config.DataBaseIntegration(db =>
            {
                db.ConnectionProvider<DriverConnectionProvider>();
            });

            if (dbType == DatabaseType.Oracle)
            {
                _config.DataBaseIntegration(db =>
                {
                    db.Dialect<Oracle10gDialect>();
                    db.Driver<OracleDataClientDriver>();
                    db.Batcher<OracleDataClientBatchingBatcherFactory>();
                    db.BatchSize = 200;
                });
            }
            else if (dbType == DatabaseType.SqlServer)
            {
                _config.DataBaseIntegration(db =>
                {
                    db.Dialect<MsSql2008Dialect>();
                    db.Driver<Sql2008ClientDriver>();
                    db.Batcher<SqlClientBatchingBatcherFactory>();
                    db.BatchSize = 200;
                });
            }
            else if (dbType == DatabaseType.SQLite)
            {
                _config.DataBaseIntegration(db =>
                {
                    db.Dialect<SQLiteDialect>();
                    db.Driver<SQLite20Driver>();
                });
            }

            return this;
        }

        public IDatabaseBuilder ConnectionString(string connectionString)
        {
            _config.DataBaseIntegration(db =>
            {
                db.ConnectionString = connectionString;
            });

            return this;
        }

        public IDatabaseBuilder Timeout(int timeout)
        {
            _config.DataBaseIntegration(db =>
            {
                db.Timeout = (byte)timeout;
            });

            return this;
        }

        public IDatabaseBuilder AddMappings(IEnumerable<Type> types)
        {
            ModelMapper mapper = new ModelMapper();
            mapper.AddMappings(types);

            var hbmMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();

            _config.AddMapping(hbmMapping);

            _hasAddedMappingClass = true;

            return this;
        }

        public DatabaseModel Build()
        {
            //是否添加映射实体类，如果没有添加则通过TypeSearcher工具来得到所有实体类型（ClassMapping<>）
            if (!_hasAddedMappingClass)
            {
                var mapping = TypeSearcher.BuildReferencedAssemblies().ConcreteTypes().Where(a => a.IsAssignableByGenericType(typeof(ClassMapping<>)));
                var mapper = new ModelMapper();
                mapping.Each(map => mapper.AddMapping(map));
                var hbmMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
                _config.AddMapping(hbmMapping);
            }

            return new DatabaseModel { Name = _name, SessionFactory = _config.BuildSessionFactory() };
        }

        public void BuildSchema()
        {
            SchemaExport se = new SchemaExport(_config);
            se.Execute(false, true, false);
        }
    }
}
